﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace WgpgGUI
{
    public class SearchTextBox : TextBox
    {
        private static readonly DependencyPropertyKey HasTextPropertyKey = DependencyProperty.RegisterReadOnly("HasText", typeof(Boolean), typeof(SearchTextBox), new PropertyMetadata());
        private static readonly DependencyPropertyKey IsMouseLeftButtonDownPropertyKey = DependencyProperty.RegisterReadOnly("IsMouseLeftButtonDown", typeof(Boolean), typeof(SearchTextBox), new PropertyMetadata());

        public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText", typeof(String), typeof(SearchTextBox));
        public static readonly DependencyProperty LabelTextColorProperty = DependencyProperty.Register("LabelTextColor", typeof(Brush), typeof(SearchTextBox));
        public static readonly DependencyProperty HasTextProperty = HasTextPropertyKey.DependencyProperty;
        public static readonly DependencyProperty IsMouseLeftButtonDownProperty = IsMouseLeftButtonDownPropertyKey.DependencyProperty;
        public static readonly DependencyProperty SearchEventTimeDelayProperty = DependencyProperty.Register("SearchEventTimeDelay", typeof(Duration), typeof(SearchTextBox), new FrameworkPropertyMetadata(new Duration(new TimeSpan(0, 0, 0, 0, 500)), new PropertyChangedCallback(OnSearchEventTimeDelayChanged)));

        public static readonly RoutedEvent SearchEvent = EventManager.RegisterRoutedEvent("Search", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SearchTextBox));

        private readonly DispatcherTimer _searchEventDelayTimer;

        static SearchTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchTextBox), new FrameworkPropertyMetadata(typeof(SearchTextBox)));
        }

        public SearchTextBox()
        {
            _searchEventDelayTimer = new DispatcherTimer
            {
                Interval = SearchEventTimeDelay.TimeSpan
            };
            _searchEventDelayTimer.Tick += OnSeachEventDelayTimerTick;
        }

        private void OnSeachEventDelayTimerTick(Object o, EventArgs e)
        {
            _searchEventDelayTimer.Stop();
            RaiseSearchEvent();
        }

        private static void OnSearchEventTimeDelayChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            SearchTextBox stb = o as SearchTextBox;
            if (stb == null)
                return;

            stb._searchEventDelayTimer.Interval = ((Duration)e.NewValue).TimeSpan;
            stb._searchEventDelayTimer.Stop();
        }

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);

            HasText = Text.Length != 0;
            _searchEventDelayTimer.Stop();
            _searchEventDelayTimer.Start();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            Border iconBorder = GetTemplateChild("SearchTextBox_IconBorder") as Border;
            if (iconBorder == null)
                return;

            iconBorder.MouseLeftButtonDown += IconBorder_MouseLeftButtonDown;
            iconBorder.MouseLeftButtonUp += IconBorder_MouseLeftButtonUp;
            iconBorder.MouseLeave += IconBorder_MouseLeave;
        }

        private void IconBorder_MouseLeftButtonDown(Object obj, MouseButtonEventArgs e)
        {
            IsMouseLeftButtonDown = true;
        }

        private void IconBorder_MouseLeftButtonUp(Object obj, MouseButtonEventArgs e)
        {
            if (IsMouseLeftButtonDown)
            {
                Text = String.Empty;
                IsMouseLeftButtonDown = false;
            }
        }

        private void IconBorder_MouseLeave(Object obj, MouseEventArgs e)
        {
            IsMouseLeftButtonDown = false;
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                Text = String.Empty;
            else if (e.Key == Key.Return || e.Key == Key.Enter)
            {
                _searchEventDelayTimer.Stop();
                RaiseSearchEvent();
            }
            else
                base.OnKeyDown(e);
        }

        private void RaiseSearchEvent()
        {
            RoutedEventArgs args = new RoutedEventArgs(SearchEvent);
            RaiseEvent(args);
        }

        public String LabelText
        {
            get { return (String)GetValue(LabelTextProperty); }
            set { SetValue(LabelTextProperty, value); }
        }

        public Brush LabelTextColor
        {
            get { return (Brush)GetValue(LabelTextColorProperty); }
            set { SetValue(LabelTextColorProperty, value); }
        }

        public Boolean HasText
        {
            get { return (Boolean)GetValue(HasTextProperty); }
            private set { SetValue(HasTextPropertyKey, value); }
        }

        public Duration SearchEventTimeDelay
        {
            get { return (Duration)GetValue(SearchEventTimeDelayProperty); }
            set { SetValue(SearchEventTimeDelayProperty, value); }
        }

        public Boolean IsMouseLeftButtonDown
        {
            get { return (Boolean)GetValue(IsMouseLeftButtonDownProperty); }
            private set { SetValue(IsMouseLeftButtonDownPropertyKey, value); }
        }

        public event RoutedEventHandler Search
        {
            add { AddHandler(SearchEvent, value); }
            remove { RemoveHandler(SearchEvent, value); }
        }
    }
}
